typedef unsigned char uint8_t;

// QEMU virt 上 UART 设备的内存映射基地址
#define UART_BASE 0x10000000L

// UART 寄存器偏移
#define RHR 0 // Receive Holding Register, 只读
#define THR 0 // Transmit Holding Register, 只写
#define LSR 5 // Line Status Register

// LSR 中特定位的掩码
#define LSR_RX_READY (1 << 0) // LSR 第 0 位表示可接收新数据, Data-ready (DR) indicator for the receiver.
#define LSR_TX_EMPTY (1 << 5) // LSR 第 5 位表示可发送新数据, Transmitter holding register empty (THRE) indicator.

// 指向 UART 基地址的指针
volatile uint8_t *uart = (uint8_t *)UART_BASE;

// 向 UART 发送一个字符
void uart_putc(char c) {
    // 轮询 LSR 寄存器，直到可发送数据 (LSR 的第 5 位为 1)
    while ((uart[LSR] & LSR_TX_EMPTY) == 0);
    // 写入字符到 THR 寄存器, 自动触发数据发送
    uart[THR] = c;
}

// 从 UART 接收一个字符
char uart_getc() {
    // 轮询 LSR 寄存器，直到有数据可读 (LSR 的第 0 位为 1)
    while ((uart[LSR] & LSR_RX_READY) == 0);
    // 从 RHR 寄存器读取字符, 自动使 LSR_RX_READY 清零
    return uart[RHR];
}

// 向 UART 发送一个字符串(以 '\0' 结尾)
void uart_puts(const char *s) {
    while (*s) {
        uart_putc(*s++);
    }
}

// 输入行缓冲区
uint8_t buf[1024];
// 缓冲区指针
uint8_t buf_ptr = 0;

// 主函数
void main() {
    // 控制 UART 接收一个字符并立即发回, 并在接收到回车符时打印整行内容
    while (1) {
        // 获取一个字符
        char c = uart_getc();
        // 立即回显该字符
        uart_putc(c);
        // 若收到回车符, 额外发送一个换行符, 并打印已输入的整行内容
        if (c == '\r') {
            uart_puts("\r\n");
            uart_puts("Typed: ");
            buf[buf_ptr] = 0; // 在字符串末尾添加 '\0' 终止符
            uart_puts((const char *)buf);
            uart_puts("\r\n");
            buf_ptr = 0; // 重置缓冲区指针, 准备接收下一行
        } 
        // 若收到退格符, 删除缓冲区中最后一个字符
        else if (c == 0x7f) { // 0x7f 是 ASCII 退格符
            if (buf_ptr > 0) {
                buf_ptr--;
                // 发送退格符, 空格, 再发送退格符, 实现删除效果
                uart_puts("\b \b");
            }
        }
        // 普通字符, 存入缓冲区
        else {
            buf[buf_ptr++] = c;
        }
    }
}
